/* Provide a read function for a class member */

#ifndef MC_ACCESSOR_READ_HPP
#define MC_ACCESSOR_READ_HPP

#include <cassert>
#include <cstddef>
#include <sstream>

/* TR1 header */
#ifdef __GLIBCXX__
	#include <tr1/type_traits>
#else
	#include <type_traits>
#endif

#include <memchart/accessor_format.hpp>
#include <memchart/types.hpp>

namespace memchart
{
	/*
	 * Choose a read implementation depending on T properties.
	 */
	template <bool IsArray,	typename C, typename T, T C::* M>
	struct accessor_read_impl
	{
		static string read (const void *p)
		{
			assert(p != NULL);

			const C & obj = *reinterpret_cast<const C *>(p);

			std::ostringstream ss;

			if (ss << accessor_format(obj.*M))
				return ss.str();
			else
				return "?";
		}
	};

	/* T is an array */
	template <typename C, typename T, T C::* M>
	struct accessor_read_impl<true, C, T, M>
	{
		static string read (const void *p)
		{
			assert(p != NULL);

			const C & obj = *reinterpret_cast<const C *>(p);

			std::ostringstream ss;

			ss << "{";
			for (size_t i = 0; i < std::tr1::extent<T>::value; ++i)
			{
				if (i != 0)
					ss << ", ";
				ss << accessor_format((obj.*M)[i]);
			}

			if (ss << "}")
				return ss.str();
			else
				return "?";
		}
	};


	template <typename C, typename T, T C::* M>
	struct accessor_read :
		accessor_read_impl<std::tr1::is_array<T>::value, C, T, M>
	{ };
}

#endif /* MC_ACCESSOR_READ_HPP */
